<?php

namespace app\shop\library\pay\implements;

use app\shop\library\pay\PayInterface;
use app\shop\library\ShopAuth;
use app\shop\library\ShopHelper;
use ba\Exception;
use Yansongda\Artful\Exception\ContainerException;
use Yansongda\Artful\Exception\InvalidParamsException;
use Yansongda\Artful\Exception\ServiceNotFoundException;
use Yansongda\Pay\Pay;
use Yansongda\Pay\Provider\Wechat;

class WxpayImplement implements PayInterface
{
    /**
     * 支付配置
     * @var array
     */
    private array $config;

    public function __construct()
    {
        $payConfig = ShopHelper::get_setting_group('wxpay');

        $this->config = [
            'wechat' => [
                'default' => [
                    'appid'                   => $payConfig['wxpay_app_id'],
                    'mini_app_id'             => ShopHelper::get_setting('miniapp_id'),
                    'mch_id'                  => $payConfig['wxpay_mch_id'],
                    'mch_secret_key'          => $payConfig['wxpay_secret_key'],
                    'mch_public_cert_path'    => $payConfig['wxpay_public_cert'],
                    'mch_secret_cert'         => $payConfig['wxpay_private_cert'],
                    'notify_url'              => '',
                    'mode'                    => Pay::MODE_NORMAL,
                    'wechat_public_cert_path' => [
                        '45F59D4DABF31918AFCEC556D5D2C6E376675D57' => __DIR__ . '/Cert/wechatpay_45F***D57.pem'
                    ],
                ]
            ],
            'logger' => [
                'enable'   => true,
                'file'     => root_path() . 'runtime/log/wxpay/wxpay.log', // 请注意权限
                'level'    => app()->isDebug() ? 'debug' : 'info', // 建议生产环境等级调整为 info，开发环境为 debug
                'type'     => 'daily', // optional, 可选 daily， daily 时将按时间自动划分文件.
                'max_file' => 30, // optional, 当 type 为 daily 时有效，默认 30 天
            ],
            'http'   => [
                'timeout'         => 10.0,
                'connect_timeout' => 10.0
            ],
        ];
    }

    /**
     * 检查支付用户信息
     * @return array
     * @throws Exception
     */
    private function getPayUser(): array
    {
        $user = ShopAuth::instance()->getUser();

        if (is_null($user)) {
            throw new Exception('支付用户信息异常,请刷新');
        }

        return $user->toArray();
    }

    /**
     * 支付
     * @param array $params
     * @return array
     * @throws Exception
     */
    public function pay(array $params): array
    {
        $user = $this->getPayUser();

        $order = [
            'out_trade_no' => time() . '',
            'description'  => 'subject-测试',
            'amount'       => [
                'total' => 1,
            ],
            'payer'        => [
                'openid' => $user['openid'],
            ],
        ];

        return Pay::wechat($this->config)->mp($order)->toArray();
    }

    /**
     * 小程序支付
     * @param array $params
     * @return array
     * @throws Exception
     */
    public function miniapp(array $params): array
    {
        $user = $this->getPayUser();

        $order = [
            'out_trade_no' => $params['out_trade_no'],
            'description'  => $params['desc'],
            'amount'       => [
                'total'    => intval($params['amount'] * 100),    //单位是分
                'currency' => 'CNY',
            ],
            'payer'        => [
                'openid' => $user['openid']
            ]
        ];

        $result = Pay::wechat($this->config)->mini($order);

        return $result->toArray();
    }

    /**
     * 退款
     * @param array $params
     * @return array
     * @throws ContainerException
     * @throws InvalidParamsException
     * @throws ServiceNotFoundException
     */
    public function refund(array $params): array
    {
        $order = [
            'out_trade_no'  => $params['out_trade_no'],
            'out_refund_no' => $params['out_trade_no'] . '_' . time(),
            'amount'        => [
                'refund'   => intval($params['refund_amount'] * 100),   //单位为分
                'total'    => intval($params['total_amount'] * 100),
                'currency' => 'CNY',
            ],
            '_action'       => $params['_action'],
        ];

        $result = Pay::wechat($this->config)->refund($order);

        return $result->toArray();
    }

    /**
     * 设置支付配置
     * @param array $config
     * @return $this
     */
    public function setConfig(array $config): static
    {
        $this->config = array_merge($this->config, ...$config);

        return $this;
    }

    /**
     * 设置支付回调地址
     * @param string $notifyUrl
     * @param string $configGroup
     * @return wxpayImplement
     */
    public function setNotifyUrl(string $notifyUrl, string $configGroup = 'default'): static
    {
        if (filter_var($notifyUrl, FILTER_VALIDATE_URL) === false) {
            $notifyUrl = ShopHelper::full_api_url() . '/' . ltrim($notifyUrl, '/');
        }

        $this->config['wechat'][$configGroup]['notify_url'] = $notifyUrl;

        return $this;
    }

    public function setReturnUrl(string $returnUrl, string $configGroup = 'default'): static
    {
        return $this;
    }

    /**
     * 获取支付对象
     * @return Wechat
     */
    public function getPayObject(): Wechat
    {
        return Pay::wechat($this->config);
    }

    /**
     * 设置日志文件路径
     * @param string $filPath
     * @return $this
     */
    public function setLogFilePath(string $filPath): static
    {
        $this->config['logger']['file'] = $filPath;

        return $this;
    }

    /**
     * 查询
     * @param array $params
     * @return array
     * @throws ContainerException
     * @throws InvalidParamsException
     * @throws ServiceNotFoundException
     */
    public function query(array $params): array
    {
        $order = [
            'out_trade_no' => $params['out_trade_no'],
            '_action'      => $params['_action']
        ];

        return Pay::wechat($this->config)->query($order)->toArray();
    }

    /**
     * 查询退款
     * @param array $params
     * @return array
     * @throws ContainerException
     * @throws InvalidParamsException
     * @throws ServiceNotFoundException
     */
    public function queryRefund(array $params): array
    {
        $order = [
            'out_refund_no' => $params['out_trade_no'],
            '_action'       => $params['_action'],
        ];

        return Pay::wechat($this->config)->query($order)->toArray();
    }
}
